import { Viewer } from "cesium";
import * as satellite from "satellite.js";
import * as Cesium from "cesium";

const now = new Date("2025-03-17 4:37:00").getTime();

/**
 * 计算 startTime && endTime
 * minsPerInterval: 一圈分钟数
 */
function getStratEndTime(minsPerInterval: number) {
  // const startTimeStamp = Date.now();
  const startTimeStamp = now;

  // 结束时间为一圈后的时间
  const endTimeStamp = startTimeStamp + minsPerInterval * 60 * 1000;
  let startTime = Cesium.JulianDate.fromDate(new Date(startTimeStamp));
  startTime = Cesium.JulianDate.addHours(startTime, 8, new Cesium.JulianDate());
  let endTime = Cesium.JulianDate.fromDate(new Date(endTimeStamp));
  endTime = Cesium.JulianDate.addHours(endTime, 8, new Cesium.JulianDate());
  return {
    startTime,
    endTime,
  };
}
/**
 * 计算SampledPositionProperty
 * satrec: satellite.twoline2satrec返回值
 * minsPerInterval：一圈分钟数
 */
function getPositionSample(satrec: any, minsPerInterval: number) {
  const positionProperty = new Cesium.SampledPositionProperty();
  const positionArray = [];
  // 每5分钟采样一个点
  const sampleInterval = 5;
  for (let i = 0; i <= minsPerInterval; i += sampleInterval) {
    // 从现在起，获取一圈内每分钟的位置;生成一个数组，用作插值
    const curTimeDate = new Date(now + i * 60 * 1000);
    var positionAndVelocity = satellite.propagate(satrec, curTimeDate); // 此方法拿到的是惯性系坐标
    // var gmst = satellite.gstime(new Date(curTimeDate))
    // 惯性
    const positionEci: any = positionAndVelocity.position;
    // 惯性转成地固
    // const positionEcf = satellite.eciToEcf(positionEci, gmst)
    // julian日期
    const curJulianDate = Cesium.JulianDate.fromDate(curTimeDate);
    // 北京时
    const d = Cesium.JulianDate.addHours(
      curJulianDate,
      8,
      new Cesium.JulianDate()
    );

    const position = new Cesium.Cartesian3(
      positionEci.x * 1000,
      positionEci.y * 1000,
      positionEci.z * 1000
    );
    positionArray.push(position);
    positionProperty.addSample(
      d,
      // 这里使用惯性或者地固都行，但是地固系在端点处偏差较大，因此使用惯性系
      new Cesium.Cartesian3(
        positionEci.x * 1000,
        positionEci.y * 1000,
        positionEci.z * 1000
      )
    );
  }
  return { positionProperty, positionArray };
}
const viewerSatelliteMixin = (viewer: Viewer) => {
  if (!viewer.viewerMixins) {
    viewer.viewerMixins = {};
  }

  const viewerMixins = viewer.viewerMixins;

  const addSatelliteFromTle = (tle: [string, string], color: string) => {
    const id = Cesium.createGuid();
    const [tleLine1, tleLine2] = tle;
    const satrec = satellite.twoline2satrec(tleLine1, tleLine2);
    let totalIntervalsInDay = satrec.no * 1440 * 0.159155; //1440 = min && 0.159155 = 1turn
    // 获得运行一圈的分钟数
    let minsPerInterval = 1440 / totalIntervalsInDay; // mins for 1 revolution around earth

    // 获取startTime && endTime
    const { startTime, endTime } = getStratEndTime(minsPerInterval);

    viewer.clock.startTime = startTime.clone();
    viewer.clock.stopTime = endTime.clone();
    viewer.clock.currentTime = startTime.clone();
    viewer.clock.multiplier = 100; // 设置播放速度,数值越大,卫星转动越快
    viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP;
    // 获取positionProperty
    const { positionProperty, positionArray } = getPositionSample(
      satrec,
      minsPerInterval
    );

    // 使用Primitive方式绘制航迹
    const polylineGeometry = new Cesium.PolylineGeometry({
      positions: positionArray,
      width: 2.0,
    });

    const polylineInstance = new Cesium.GeometryInstance({
      geometry: polylineGeometry,
      attributes: {
        color: Cesium.ColorGeometryInstanceAttribute.fromColor(
          Cesium.Color.fromCssColorString(color)
        ),
      },
    });

    viewer.scene.primitives.add(
      new Cesium.Primitive({
        geometryInstances: polylineInstance,
        appearance: new Cesium.PolylineMaterialAppearance({
          material: Cesium.Material.fromType("PolylineGlow", {
            glowPower: 0.2,
            color: Cesium.Color.fromCssColorString(color),
          }),
        }),
      })
    );

    viewer.entities.add({
      id,
      name: "卫星",
      availability: new Cesium.TimeIntervalCollection([
        // 时间区间
        new Cesium.TimeInterval({
          start: startTime,
          stop: endTime,
        }),
      ]),
      position: positionProperty,
      orientation: new Cesium.VelocityOrientationProperty(positionProperty), // 方向

      model: {
        uri: "/static/model/Satellite.gltf",
        minimumPixelSize: 128,
        silhouetteColor: Cesium.Color.fromCssColorString(color),
        silhouetteSize: 2.0,
      },
      ellipsoid: {
        radii: new Cesium.Cartesian3(100000.0, 100000.0, 100000.0),
        minimumClock: Cesium.Math.toRadians(-45.0),
        maximumClock: Cesium.Math.toRadians(45.0),
        minimumCone: Cesium.Math.toRadians(85.0),
        maximumCone: Cesium.Math.toRadians(95.0),
        material: Cesium.Color.fromCssColorString(color).withAlpha(0.3),
        outline: true,
        outlineColor: Cesium.Color.fromCssColorString(color),
        outlineWidth: 2.0,
        stackPartitions: 32,
        slicePartitions: 32,
      },
    });

    return id;
  };

  Object.defineProperties(viewerMixins, {
    addSatelliteFromTle: {
      get: function () {
        return addSatelliteFromTle;
      },
    },
  });
};

export default viewerSatelliteMixin;
